package com.tonann.app.task;

import com.tonann.app.domain.*;
import com.tonann.app.service.*;
import com.tonann.app.utils.NumberUtil;
import com.tonann.common.core.redis.RedisCache;
import com.tonann.common.utils.uuid.UUID;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Service
public class AnalyseTask {

    @Autowired
    private IAppSensorService sensorService;

    @Autowired
    private IAppDeviceService deviceService;

    @Autowired
    private IAppFaultRuleService faultRuleService;

    @Autowired
    private IAppFaultService faultService;

    @Autowired
    private IAppFaultHandleService faultHandleService;

    @Autowired
    private IAppFaultHandleRecordService faultHandleRecordService;

    @Autowired
    private RedisCache redisCache;

    public int faultAnalyse(AppSensor appSensor) {
        AppFaultRule faultRule = appSensor.getFaultRule();
        if (faultRule == null || faultRule.getRuleValueToplimit() == null || faultRule.getRuleValueBottomlimit() == null) {
            return 0;
        }
        try {
            AppSensor sensor = appSensor;
            String newValue = sensor.getValue();
            if (appSensor.getFaultRuleId() != 1L) {
                String top = faultRule.getRuleValueToplimit();
                String bottom = faultRule.getRuleValueBottomlimit();
                BigDecimal topBigDecimal = new BigDecimal(top);
                BigDecimal bottomBigDecimal = new BigDecimal(bottom);
                BigDecimal newValueBigDecimal = new BigDecimal(newValue);
                if (faultRule.getRuleCode() != null && faultRule.getRuleCode().contains("multi")) {
                    String describe = faultRule.getRuleDescribe();
                    String[] describes = describe.split("&");
                    Map<Integer, String> alarmMap = new LinkedHashMap<>();
                    String regEx = "[^0-9]";
                    Pattern p = Pattern.compile(regEx);
                    for (String str : describes) {
                        Matcher m = p.matcher(str);
                        String num = m.replaceAll("").trim();
                        alarmMap.put(Integer.parseInt(num), str.replace(num, ""));
                    }
                    Set<Integer> keySet = alarmMap.keySet();
                    String v = NumberUtil.toBinary(newValueBigDecimal.intValue(), 16);
                    for (Integer key : keySet) {
                        Character character = v.charAt(key);
                        if (character.equals('1')) {
                            // 触发告警
                            addFault(sensor, faultRule, "1", alarmMap.get(key));
                            return  1;
                        } else {
                            removeFault(sensor, faultRule);
                            return  -1;
                        }
                    }
                } else if (topBigDecimal.compareTo(bottomBigDecimal) == 0) {
                    if (newValueBigDecimal.floatValue() == bottomBigDecimal.floatValue()) {
//                        System.out.println("value:" + newValue + "++++" + "sensorDto:" + sensor.getValue() + "////sensorName:" + sensor.getSensorName() + "触发告警");
                        addFault(sensor, faultRule, newValue);
                        return 1;
                    } else {
                        removeFault(sensor,faultRule);
                        return  -1;
                    }
                } else {
                    if (newValueBigDecimal.floatValue() > topBigDecimal.floatValue() || newValueBigDecimal.floatValue() <= bottomBigDecimal.floatValue()) {
                        // 触发告警
//                        System.out.println("触发告警:" + sensor.getSensorName() + "，报警名称：" + faultRule.getRuleName());
                        addFault(sensor, faultRule, newValue);
                        return 1;
                    } else {
                        removeFault(sensor, faultRule);
                        return  -1;
                    }
                }
            }
        } catch (Exception ignored) {
        }
        return 0;
    }

    private void addFault(AppSensor sensor, AppFaultRule faultRule, String value) {
        if (sensor == null) {
            return;
        }
        AppFault fault = new AppFault();
        fault.setSensorId(sensor.getSensorId());
        fault.setFaultRuleId(faultRule.getFaultRuleId());
        fault.setFaultValue(value);
        fault.setFaultName(faultRule.getRuleName());
        fault.setFaultCode(UUID.fastUUID().toString(true).replace("-", ""));
        if (sensor.getDevice() == null && sensor.getDeviceId() != null) {
            AppDevice appDevice = deviceService.selectAppDeviceByDeviceId(sensor.getDeviceId());
            if (appDevice != null) {
                sensor.setDevice(appDevice);
            }
        }
        fault.setDeviceType(sensor.getDevice().getType());
        fault.setDeviceId(sensor.getDeviceId());
        String userName = "admin";
        fault.setCreateBy(userName);
        fault.setUpdateBy(userName);
        fault.setCreateTime(new Timestamp(new Date().getTime()));
        fault.setUpdateTime(new Timestamp(new Date().getTime()));
        faultService.insertAppFault(fault);
        Long deviceId = sensor.getDeviceId();
        if (deviceId != null) {
            AppDevice device = deviceService.selectAppDeviceByDeviceId(deviceId);
            if (device != null) {
                device.setIsException("1");
                deviceService.updateAppDeviceStatus(device);
                redisCache.deleteObject("app_fault_list::device_id::" + device.getDeviceId());
            }
        }
//        addFaultSum(fault);
//        saveDeviceFault(sensor.getDevice());
    }


    private void addFault(AppSensor sensor, AppFaultRule faultRule, String value, String name) {
        if (sensor == null) {
            return;
        }
        AppFault fault = new AppFault();
        fault.setSensorId(sensor.getSensorId());
        fault.setFaultRuleId(faultRule.getFaultRuleId());
        fault.setFaultValue(value);
        fault.setFaultName(name);
        fault.setFaultCode(UUID.fastUUID().toString(true).replace("-", ""));
        fault.setDeviceType(sensor.getDevice().getType());
        fault.setDeviceId(sensor.getDeviceId());
        String userName = "admin";
        fault.setCreateBy(userName);
        fault.setUpdateBy(userName);
        fault.setCreateTime(new Timestamp(new Date().getTime()));
        fault.setUpdateTime(new Timestamp(new Date().getTime()));
        faultService.insertAppFault(fault);
//        addFaultSum(fault);
//        saveDeviceFault(sensor.getDevice());
        Long deviceId = sensor.getDeviceId();
        if (deviceId != null) {
            AppDevice device = deviceService.selectAppDeviceByDeviceId(deviceId);
            if (device != null) {
                device.setIsException("1");
                deviceService.updateAppDeviceStatus(device);
                redisCache.deleteObject("app_fault_list::device_id::" + device.getDeviceId());
            }
        }
    }

    private void removeFault(AppSensor sensor, AppFaultRule faultRule) {
        AppFault appFault = new AppFault();
        appFault.setSensorId(sensor.getSensorId());
        appFault.setFaultRuleId(faultRule.getFaultRuleId());
        List<AppFault> faultList = faultService.selectAppFaultList(appFault);
        Set<Long> set = new HashSet<>();
        if (faultList.size() > 0) {
            faultList.sort(new Comparator<AppFault>() {
                @Override
                public int compare(AppFault o1, AppFault o2) {
                    if (o1.getCreateTime().getTime() > o2.getCreateTime().getTime()) {
                        return 1;
                    } else {
                        return -1;
                    }
                }
            });
            for (AppFault a : faultList) {
                set.add(a.getFaultId());
            }
            List<AppFaultHandle> faultHandleList = faultHandleService.selectAppFaultHandleListByFaultIds(
                    set.toArray(new Long[set.size()])
            );

            faultHandleService.updateAllSameFaultsByModbus(faultHandleList);
            redisCache.deleteObject("app_fault_list::device_id::" + sensor.getDeviceId());
            Long deviceId = sensor.getDeviceId();
            if (deviceId != null) {
                AppDevice device = deviceService.selectAppDeviceByDeviceId(deviceId);
                if (device != null) {
                    device.setIsException("0");
                    deviceService.updateAppDeviceStatus(device);
                }
            }
        }
    }

    public void analyseList(List<AppSensor> updateList) {
        sensorService.updateByModbusList(updateList);
    }

//    private void addFaultSum(AppFault fault) {
//        List<SysDashboardDto> sysDashboardDtoList = sysDashboardService.queryAll(new SysDashboardQueryCriteria());
//        if (sysDashboardDtoList != null && sysDashboardDtoList.size() > 0) {
//            SysDashboardDto sysDashboardDto = sysDashboardDtoList.get(0);
//            if (sysDashboardDto.getTotalFault() == null) {
//                sysDashboardDto.setTotalFault(0L);
//            }
//            Long totalFault = sysDashboardDto.getTotalFault();
//            totalFault++;
//            sysDashboardDto.setTotalFault(totalFault);
//            sysDashboardService.update(sysDashboardMapper.toEntity(sysDashboardDto));
//        } else {
//            SysDashboard sysDashboard = new SysDashboard();
//            sysDashboard.setTotalFault(1L);
//            sysDashboardService.create(sysDashboard);
//        }
//        List<BigdataDashboardDto> list = bigdataDashboardService.queryAll(new BigdataDashboardQueryCriteria());
//        if (list.size() > 0) {
//            BigdataDashboardDto bigdataDashboardDto = list.get(0);
//            BigdataDashboard bigdataDashboard = new BigdataDashboard();
//            bigdataDashboard.setWeekFault(bigdataDashboardDto.getWeekFault() + 1);
//            bigdataDashboard.setId(bigdataDashboardDto.getId());
//            bigdataDashboard.setTodayEnergy(bigdataDashboardDto.getTodayEnergy());
//            bigdataDashboard.setMonthEnergy(bigdataDashboardDto.getMonthEnergy());
//            bigdataDashboard.setYearEnergy(bigdataDashboardDto.getYearEnergy());
//            bigdataDashboard.setMonthFault(bigdataDashboardDto.getMonthFault() + 1);
//            bigdataDashboard.setYearFault(bigdataDashboardDto.getYearFault() + 1);
//            bigdataDashboard.setTotalPower(bigdataDashboardDto.getTotalPower());
//            bigdataDashboard.setPowerRate(bigdataDashboardDto.getPowerRate());
//            List<DeviceDto> deviceDtoList = deviceService.queryAll(new DeviceQueryCriteria());
//            FaultHandleQueryCriteria faultHandleQueryCriteria = new FaultHandleQueryCriteria();
//            faultHandleQueryCriteria.setIsChecked(false);
//            List<FaultHandleDto> faultHandleDtoList = faultHandleService.queryAll(faultHandleQueryCriteria);
//            List<Long> deviceIdList = new ArrayList<>();
//            for (FaultHandleDto faultHandleDto : faultHandleDtoList) {
//                FaultDto faultDto = faultHandleDto.getFault();
//                if (faultDto != null) {
//                    SensorDto sensorDto = faultDto.getSensor();
//                    if (sensorDto != null) {
//                        DeviceDto deviceDto = sensorDto.getDevice();
//                        if (deviceDto != null) {
//                            if (!deviceIdList.contains(deviceDto.getDeviceId())) {
//                                deviceIdList.add(deviceDto.getDeviceId());
//                            }
//                        }
//                    }
//                }
//            }
//            if (!deviceIdList.contains(fault.getSensor().getDevice().getDeviceId())) {
//                deviceIdList.add(fault.getSensor().getDevice().getDeviceId());
//            }
//            int availability = (deviceDtoList.size() - deviceIdList.size()) * 100 / deviceDtoList.size();
//            bigdataDashboard.setAvailability(availability * 100);
//            List<FaultHandle> faultHandleDtos = faultHandleService.findTodayData();
//            int checkedCount = 0;
//            for (FaultHandle faultHandleDto : faultHandleDtos) {
//                if (faultHandleDto.getIsChecked()) {
//                    checkedCount++;
//                }
//            }
//            bigdataDashboard.setFaultRate((checkedCount * 100 / (faultHandleDtos.size())));
//            bigdataDashboardService.update(bigdataDashboard);
////            System.out.println(bigdataDashboard.getWeekFault() + "+++dashboard");
//        } else {
//            BigdataDashboard bigdataDashboard = new BigdataDashboard();
//            bigdataDashboard.setWeekFault(1L);
//            bigdataDashboard.setTodayEnergy(0F);
//            bigdataDashboard.setMonthEnergy(0F);
//            bigdataDashboard.setYearEnergy(0F);
//            bigdataDashboard.setMonthFault(1L);
//            bigdataDashboard.setYearFault(1L);
//            bigdataDashboard.setTotalPower(0L);
//            bigdataDashboard.setPowerRate(0);
//            List<DeviceDto> deviceDtoList = deviceService.queryAll(new DeviceQueryCriteria());
//            FaultHandleQueryCriteria faultHandleQueryCriteria = new FaultHandleQueryCriteria();
//            faultHandleQueryCriteria.setIsChecked(false);
//            List<FaultHandleDto> faultHandleDtoList = faultHandleService.queryAll(faultHandleQueryCriteria);
//            List<Long> deviceIdList = new ArrayList<>();
//            for (FaultHandleDto faultHandleDto : faultHandleDtoList) {
//                FaultDto faultDto = faultHandleDto.getFault();
//                if (faultDto != null) {
//                    SensorDto sensorDto = faultDto.getSensor();
//                    if (sensorDto != null) {
//                        DeviceDto deviceDto = sensorDto.getDevice();
//                        if (deviceDto != null) {
//                            if (!deviceIdList.contains(deviceDto.getDeviceId())) {
//                                deviceIdList.add(deviceDto.getDeviceId());
//                            }
//                        }
//                    }
//                }
//            }
//            if (!deviceIdList.contains(fault.getSensor().getDevice().getDeviceId())) {
//                deviceIdList.add(fault.getSensor().getDevice().getDeviceId());
//            }
//            int availability = (deviceDtoList.size() - deviceIdList.size()) * 100 / deviceDtoList.size();
//            bigdataDashboard.setAvailability(availability * 100);
//            List<FaultHandle> faultHandleDtos = faultHandleService.findTodayData();
//            int checkedCount = 0;
//            for (FaultHandle faultHandleDto : faultHandleDtos) {
//                if (faultHandleDto.getIsChecked()) {
//                    checkedCount++;
//                }
//            }
//            bigdataDashboard.setFaultRate((checkedCount * 100 / (faultHandleDtos.size())));
//            bigdataDashboardService.create(bigdataDashboard);
//        }
//    }
//
//    private void saveDeviceFault(AppDevice device) {
//        List<BigdataDashboardFaultDevice> bigdataDashboardFaultDevices = bigdataDashboardFaultDeviceRepository.findAll();
//        for (BigdataDashboardFaultDevice bigdataDashboardFaultDevice : bigdataDashboardFaultDevices) {
//            if (device.getType().equals(bigdataDashboardFaultDevice.getDevice().getType())
//                    && device.getDeviceId().equals(bigdataDashboardFaultDevice.getDeviceId())) {
//                bigdataDashboardFaultDevice.setFault(bigdataDashboardFaultDevice.getFault() + 1);
//                bigdataDashboardFaultDeviceRepository.save(bigdataDashboardFaultDevice);
////                System.out.println(bigdataDashboardFaultDevice.getFault() + "////faultDevice");
//                return;
//            }
//        }
//        BigdataDashboardFaultDevice bigdataDashboardFaultDevice = new BigdataDashboardFaultDevice();
//        bigdataDashboardFaultDevice.setFault(1L);
//        bigdataDashboardFaultDevice.setDeviceId(device.getDeviceId());
//        bigdataDashboardFaultDevice.setDeviceType(device.getType());
//        bigdataDashboardFaultDevice.setDevice(device);
//        bigdataDashboardFaultDeviceRepository.save(bigdataDashboardFaultDevice);
//    }
}
